/**
 * @file 创建远程组件的方法
 * @description 支持远程加载react | vue 组件
 * @desc 对于vue3可以通过shadow Root隔离
 */

// 按需引入，需要全局注入样式
// @ts-nocheck
const { defineComponent, onMounted, ref, createVNode, render, createApp } = Vue;
const { useState } = React;
import { cloneDeep, get as _get } from 'lodash';
const useShadowDOM = false;

const { useRef, useEffect } = React;

import memoize from 'lodash.memoize';
// message begin

// 消息服务实现（根据图片补充）
const messageService = {
    asObservable: function() {
        return {
            subscribe: function(callback) {
                // 简单的消息订阅实现
                window.addEventListener('message', callback);
                return {
                    unsubscribe: function() {
                        window.removeEventListener('message', callback);
                    }
                };
            }
        };
    }
};

// 发送消息函数（根据图片补充）
export function sendMessage(message) {
    const event = new CustomEvent('message', { detail: message });
    window.dispatchEvent(event);
}

const scripts = (function () {
    let doc = document,
        head = doc.getElementsByTagName('head')[0],
        s = 'string',
        f = false,
        push = 'push',
        readyState = 'readyState',
        onreadystatechange = 'onreadystatechange',
        list = {},
        ids = {},
        delay = {},
        scripts = {},
        scriptpath,
        urlArgs;

    function every(ar, fn) {
        for (var i = 0, j = ar.length; i < j; ++i) if (!fn(ar[i])) return f;
    }

    function each(ar, fn) {
        every(ar, function (el) {
            fn(el);
            return 1;
        });
    }

    function $script(paths, idOrDone, optDone, forceUpdate) {
        paths = paths[push] ? paths : [paths];
        var idOrDoneIsDone = idOrDone && idOrDone.call,
            done = idOrDoneIsDone ? idOrDone : optDone,
            id = idOrDoneIsDone ? paths.join('') : idOrDone,
            queue = paths.length;
    }

    function loopFn(item) {
        return item.call ? item() : list[item];
    }

    function mount(item) {
        return item.call ? item() : list[item];
    }
})();

let styleObserver; // 用于监听样式节点的插入
let isLocked = false; // 用于控制锁定状态

// 将样式插入到最后一个样式标签之后
function insertLastStyle({ container, newStyle }) {
    if (!container || !newStyle) {
        console.error('Invalid arguments: container and newStyle must be provided.');
        return;
    }

    try {
        // 查找最后一个<style>或<link>标签，并将新样式插入其后
        if (lastStyleLink) {
            container.insertBefore(newStyle, lastStyleLink.nextSibling);
        } else {
            // 如果没有现有的<style>或<link rel="stylesheet">，则直接将新样式添加到<head>的末尾
            container.appendChild(newStyle);
        }
    } catch (error) {
        console.error('Failed to insert style:', error);
    }
}

function observeStyleNodesInsertion(targetDom) {
    if (!targetDom) {
        console.error('Target DOM element must be provided.');
        return;
    }

    try {
        // 定义回调函数，处理新增的样式节点并移动到目标DOM
        const callback = function (mutationsList, observer) {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach((addedNode) => {
                        if ((addedNode.tagName === 'LINK' && addedNode.rel === 'stylesheet') || addedNode.tagName === 'STYLE') {
                            insertLastStyle({
                                container: targetDom,
                                newStyle: addedNode
                            });
                        }
                    });
                }
            }
        };

        // 创建一个观察器实例并传入回调函数
        styleObserver = new MutationObserver(callback);

        // 配置观察器选项:子节点变化
        const config = { childList: true, subtree: false };

        // 开始观察(head)的变化
        const head = document.getElementsByTagName('HEAD')[0];
        if (head) {
            styleObserver.observe(head, config);
        } else {
            console.error('Unable to find the <head> element.');
        }
    } catch (error) {
        console.error('Failed to observe style nodes insertion:', error);
    }
}

//停止监听
function stopObservingStyleNodesInsertion() {
    if (styleObserver) {
        styleObserver.disconnect(); // 取消监听
        styleObserver = null; // 清理引用
    }
}

// 等待解锁
function waitUntilUnlock() {
    return new Promise((resolve) => {
        const checkLock = () => {
            if (!isLocked) {
                resolve();
            } else {
                setTimeout(checkLock, 100);
            }
        };
        checkLock();
    });
}

// 删除指定href的script节点
function removeScriptNodes(href) {
    if (!href || typeof href !== 'string') {
        console.error('Invalid href: must be a non-empty string.');
        return;
    }

    try {
        const scripts = document.querySelectorAll(`script[src="${href}"]`);
        scripts.forEach(script => {
            if (script && script.parentNode) {
                script.remove();
            }
        });
    } catch (error) {
        console.error('Failed to remove script nodes:', error);
    }
}

// 使用示例：将所有新插入的样式节点移动到ID为'styleContainer'的DOM节点内
// observeStyleNodesInsertion('styleContainer');

function isFunction(value) {
    return typeof value === 'function';
}

function isObject(value) {
    return typeof value === 'object' && value !== null;
}

// 判断是否是影子节点
function isShadowRoot(node) {
    if (!node) {
        return false;
    }
    return node !== null && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && node.constructor.name === 'ShadowRoot';
}

function isConstructor(fn) {
    if (typeof fn === 'function' && fn.prototype.constructor === fn) {
        console.log(`${fn} is a constructor function.`);
        return true;
    } else {
        console.error(`${fn} is not a constructor or not properly imported.`);
        return false;
    }
}

//提供一个方法用于订阅消息
export function receiveMessage() {
    return messageService.asObservable();
}

//在某个组件中发布消息
//import { sendMessage } from './message.service';
//sendMessage({ type: 'NEW_USER', data: 'New user has logged in' });

//在另一个组件中订阅并接收消息
//import { receiveMessage } from './message.service';
//receiveMessage().subscribe((message) => {
// switch (message.type) {
// case 'NEW_USER':
// console.log('Received new user message:', message.data);
// break;
// //处理其他类型的消息...
// }
// });

//message end

const cache = {};

// @example
function cachedFunction(a, b, c) {
    //内部缓存对象
    //检查缓存中是否存在参数a的结果
    if (cache[a]) {
        //如果存在，比较参数b是否与缓存中的b一致
        if (cache[a].b !== b) {
            //如果b不一致，则打印错误信息
            // name 相同，但是path不同，一种特殊场景
            console.error(`Error: Cached result for ${a} exists ${cache[a].b} with a different value for current ${b}`);
        }
    } else {
        //如果不存在，则执行实际计算或其他操作，并将结果与b一起存入缓存
        const result = c();
        cache[a] = { result, b };
    }
}

function createWindowProxy() {
    const sandbox = {};
    const proxy = new Proxy(window, {
        get(target, prop) {
            if (prop in sandbox) {
                return sandbox[prop];
            }
            return target[prop];
        },
        set(target, prop, value) {
            sandbox[prop] = value;
            return true;
        }
    });
    return proxy;
}

// 获取对象属性值（根据图片补充）
function get(obj, path, defaultValue) {
    if (!isObject(obj)) return defaultValue;
    
    const keys = path.split('.');
    let result = obj;
    
    for (const key of keys) {
        if (result === null || result === undefined) {
            return defaultValue;
        }
        result = result[key];
    }
    
    return result !== undefined ? result : defaultValue;
}

// 判断对象（根据图片补充）
function isPlainObject(obj) {
    return typeof obj === 'object' && obj !== null && obj.constructor === Object;
}

// 生成资源对象（根据图片补充）
// function generateResourceObjectViaVersion({ version, name }) {
//     return {
//         js: `${version}/${name}.js`,
//         css: `${version}/${name}.css`
//     };
// }

// 获取解析器
function getResolver(generateResourceUrl) {
    return memoize(generateResourceUrl || _generateResourceUrl);
}

// 通过版本生成资源对象
function generateResourceObjectViaVersion({ version, name }) {
    // 实现根据版本生成资源对象的逻辑
    return {
        js: `${version}/${name}.js`,
        css: `${version}/${name}.css`
    };
}

// 生成组件的资源url
// TODO 目前写死了demo地址，后续需要更新到线上
// function _generateResourceUrl(name = '', {
//     version = '',
//     hasCss = true,
//     basePath = '',
//     jsPrefix = '',
//     cssPrefix = ''
// } = {
//     version: '',
//     hasCss: true,
//     basePath: '',
//     jsPrefix: '',
//     cssPrefix: ''
// }) {
//     //如果模块名称是地址，直接返回相关地址
//     if (name.indexOf('http:') >= 0) {
//         return name;
//     } else if (version) {
//         return generateResourceObjectViaVersion({
//             version,
//             name
//         });
//     } else {
//         // 默认资源生成逻辑
//         const jsUrl = `${basePath}${jsPrefix}${name}.js`;
//         const cssUrl = hasCss ? `${basePath}${cssPrefix}${name}.css` : '';
//         return {
//             js: jsUrl,
//             css: cssUrl
//         };
//     }
// }

// 动态创建组件
// 创建远程组件
// 由组件名称推导组件定义地址->通过远程加载组件地址的文件获取组件的定义(css && js) -> 挂载新组件替换旧组件
// 暴露出去的方法
// 返回一个组件，这个组件获得的数据会传递下去
// 主函数
// @desc 任何组件都将通过宿主组件进行包裹，在宿主组件中完成数据传递和生命周期管理
// @return 返回宿主组件的包裹组件
export function createRemoteComponent({
    useShadowDOM, // 是否使用shadowDom
    resourceUrl, // URL链接的定义
    version = '', // 版本
    generateResourceUrl, // 生成url地址的方法
    basePath = '', // 地址相关
    allowCors = false, // 是否使用跨域
    remoteComponentFramework = 'vue', // 远程组件属于的框架 vue | vue3 | react
    framework = 'react', // react | vue 当前框架的类型
    name, // 组件名称
    hasCss = true, // 是否有提取的css加载，
    jsPrefix = '', // 此处是默认的js路径的前缀
    cssPrefix = '' // 此处是默认的css路径的前缀
}) {
    const placeholder = () => {
        return React.createElement('div', {})
    }

    if (!name) {
        console.error('组件名称未传递')
        return placeholder
    }

    // @todo 是否使用shadow DOM
    const useShadow = useShadowDOM || _useShadowDOM
    // 当前是vue框架，创建vue占位组件
    // 分别对三种框架的宿主环境进行处理，在宿主桥接组件内部进行目标极诶件的加载
    if (framework === 'vue') {
        const bridgeComponent = Vue.component(name, {
            // 1.组件名为"conter"; 2. data 写函数; 3. template 写组件的内容(元素和触发的事件)
            data: function () {
                return {
                    count: 0
                }
            },
            // template:'span>xxxxx</span>', 
            render: function (createElement) {
                // 使用 createElement 函数来创建虚拟DOM节点
                return createElement('span', this.count)
            },
            mounted: function () {
                // 加载远程组件
                const root = useShadow ? this.$el.attachShadow({ mode: 'open' }) : this.$el;
                loadTargetComponent({
                    resourceUrl,
                    generateResourceUrl,
                    allowCors,
                    basePath,
                    jsPrefix,
                    cssPrefix,
                    hasCss,
                    remoteComponentFramework,
                    name,
                    dom: root,
                })
            }
        })
        return bridgeComponent;
        // 创建react占位组件
        // 当前框架是vue3
    } else if (framework === 'vue3') {
        // 定义一个基础组件
        // const BaseComponent = defineComponent({
        // template: `<div>我是动态创建的基础组件</div>`,
        // });
        // 动态创建组件实例
        const DynamicComponent = defineComponent({
            setup() {
                const componentRef = ref(null);
                // const root = componentRef.value.attachShadow({ mode: 'open' });
                const root = componentRef.value;
                onMounted(() => {
                    if (componentRef.value) {
                        if (componentRef.value.value) {
                            console.log('Component DOM:', componentRef.value);
                        }
                    }
                })
                return {
                    componentRef
                }
            },
            render() {
                return createVNode('div', { ref: 'componentRef' }, '动态组件内容')
            }
        })
        return DynamicComponent;
    } else if (framework === 'react') {
        const BridgeComponent = (props) => {
            const ref = useRef(null);
            useEffect(() => {
                //加载过渡组件
                load()
            })
            return React.createElement('span', { ref: ref })
        }
        const Bridge = (props) => {
            // if (!props.injectData) {
            //     props.injectData = {
            //         props.data: {},
            //         dataSource: {},
            //     }
            //   }
            // }
            // console.log('传递给目标组件的属性:', props)
            return React.createElement(BridgeComponent, props || {})
        }
        return Bridge;
    }
}

// 判断是否是react组件
function isReactComponent(candidate) {
    // 函数式组件至少是一个函数
    if (typeof candidate === 'function') {
        // 函数式组件返回值应该是React元素或者是另一个函数（无状态函数组件）
        const result = candidate({}); // 使用空对象作为props模拟调用
        return (
            (typeof result === 'object' && result !== null &&
                (result.$typeof === Symbol.for('react.element') || // JSX转换后的React元素
                    typeof result === 'function')) || // 无状态函数组件（返回另一个函数）
            false
        );
    }
    // 类组件应该是一个类且原型链上有React.Component
    else if (typeof candidate === 'object' && candidate !== null &&
        (typeof candidate.prototype === 'object' && candidate.prototype.isPrototypeOf(React.Component))) {
        return true;
    }
    return false;
}

// 通过URL加载外部样式
function loadExternalCSS(url, shadowRoot) {
    if (!url) {
        return false
    }
    const link = document.createElement('link');
    link.rel = 'stylesheet'; // 设置关系类型为stylesheet
    link.type = 'text/css'; // 设置MIME类型
    link.href = url; // 设置要加载的CSS文件的URL
    link.media = 'all'; // 对所有媒体类型生效
    const head = document.getElementsByTagName('head')[0];
    const container = isShadowRoot(shadowRoot) ? shadowRoot : head
    // 如果存在样式文件，不重复加载
    if ((container.querySelectorAll('[href="' + url + '"]') || []).length > 0) {
        return false
    } else {
        // 将link元素添加到文档头部
        container.appendChild(link);
        return true;
    }
}

//通过URL加载外部JavaScript
function loadExternalJS(url, root) {
    //获取文档的head元素
    const script = document.createElement('script'); //创建script元素
    //设置script元素的属性
    script.src = url; //设置要加载的JavaScript文件的URL
    script.type = 'text/javascript'; //设置MIME类型
    //当脚本加载完成时可选地执行一些操作
    script.onload = function () {
        console.log(`External JS file ${url} loaded successfully.`);
    };
    //处理可能的错误
    script.onerror = function () {
        console.error(`Failed to load external JS file ${url}`);
    };
    const head = document.getElementsByTagName('head')[0];
    const container = isShadowRoot(root) ? root : head
    if (container.querySelectorAll('[src="' + url + '"]').length > 0) {
        return false
    }
    //将script元素添加到文档头部
    container.appendChild(script);
    return true;
}

//添加样式前缀
function addPrefixAndAppendStyle(cssContent = '', prefix = '') {
    if (!cssContent) {
        return false
    }
    //在CSS内容中添加类名前缀
    const prefixedCSS = cssContent.replace(/(\.[a-zA-Z0-9_-]+)+/g, '.' + prefix + '$1');
    //创建一个新的style标签并将处理过的CSS内容注入
    const styleTag = document.createElement('style');
    styleTag.type = 'text/css';
    if (styleTag.styleSheet) {
        // For IE
        styleTag.styleSheet.cssText = prefixedCSS;
    } else {
        // Others
        styleTag.appendChild(document.createTextNode(prefixedCSS));
    }
    document.head.appendChild(styleTag);
    return true;
}

// 加载远程组件
async function loadVueRemoteComponent({
    propsData,
    remoteComponentFramework,
    resourceUrl,
    allowCors,
    generateResourceUrl,
    basePath,
    jsPrefix,
    cssPrefix,
    hasCss,
    name,
    dom,
    spanRoot
}) {
    let domContainer = dom
    let shadowRoot = null
    // vue3组件框架中使用shadow DOM
    if (remoteComponentFramework === 'vue3') {
        shadowRoot = isShadowRoot(domContainer) ? domContainer : domContainer.attachShadow({ mode: 'open' });
        // 创建新的span元素并添加到shadowRoot
        const span = document.createElement('span');
        shadowRoot.appendChild(span);
        domContainer = span;
    }

    // 获取定义
    const def = await getDef({
        resourceUrl,
        allowCors,
        generateResourceUrl,
        basePath,
        jsPrefix,
        cssPrefix,
        hasCss,
        name,
        dom: domContainer
    });

    // @todo 加载公共样式和依赖
    // 加载依赖
    // 加载样式
    // 加载组件

    if (remoteComponentFramework === 'vue3') {
        // 使用Vue 3的h函数、ref等创建组件
        const app = createApp({
            setup() {
                const count = ref(0);
                const increment = () => count.value++;
                return () =>
                    createVNode('button', {
                        onClick: increment
                    }, `Count: ${count.value}`)
            }
        });
        app.mount(domContainer);
    } else {
        // Vue 2方式创建组件
        new Vue({
            el: domContainer,
            data: {
                count: 0
            },
            methods: {
                increment() {
                    this.count++;
                }
            },
            template: '<button @click="increment">Count: {{ count }}</button>'
        });
    }
}

// 加载目标组件
async function loadTargetComponent(options) {
    const {
        remoteComponentFramework,
        name
    } = options;

    if (remoteComponentFramework === 'vue' || remoteComponentFramework === 'vue3') {
        return loadVueRemoteComponent(options);
    } else if (remoteComponentFramework === 'react') {
        return loadReactRemoteComponent(options);
    } else {
        console.error(`Unsupported framework: ${remoteComponentFramework} for component: ${name}`);
        return null;
    }
}

// 加载React远程组件
async function loadReactRemoteComponent({
    resourceUrl,
    allowCors,
    generateResourceUrl,
    basePath,
    jsPrefix,
    cssPrefix,
    hasCss,
    name,
    dom
}) {
    // 获取定义
    const def = await getDef({
        resourceUrl,
        allowCors,
        generateResourceUrl,
        basePath,
        jsPrefix,
        cssPrefix,
        hasCss,
        name,
        dom
    });

    if (def && isReactComponent(def)) {
        // 渲染React组件
        const root = ReactDOM.createRoot(dom);
        root.render(React.createElement(def));
        return def;
    } else {
        console.error(`Failed to load React component: ${name}`);
        return null;
    }
}

// 获取组件定义
async function getDef(options) {
    const {
        resourceUrl,
        allowCors,
        generateResourceUrl,
        basePath,
        jsPrefix,
        cssPrefix,
        hasCss,
        name,
        dom
    } = options;

    // 生成资源URL
    const url = generateResourceUrl ? generateResourceUrl(name, basePath, jsPrefix, cssPrefix) : resourceUrl;

    // 加载JS资源
    if (url) {
        await loadExternalJS(url, dom);
    }

    // 加载CSS资源
    if (hasC极诶) {
        const cssUrl = generateResourceUrl ? generateResourceUrl(name, basePath, cssPrefix, 'css') : `${resourceUrl}.css`;
        loadExternalCSS(cssUrl, dom);
    }

    // 从全局对象获取组件定义
    const globalObj = window;
    const componentDef = globalObj[name] || globalObj[`${name}Component`] || globalObj[`${name}Default`];

    if (componentDef) {
        return componentDef;
    } else {
        console.error(`Component definition not found for: ${name}`);
        return null;
    }
}

// 加载资源
function loadResources(urls) {
    urls.forEach(url => loadExternalJS(url));
}

// 从对象路径获取值
// function get(obj, path, defaultValue) {
//     const travel = regexp =>
//         String.prototype.split
//             ? path.split(regexp).filter(Boolean).reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj)
//             : null;
//     const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
//     return result === undefined || result === obj ? defaultValue : result;
// }

// 新增 _generateResourceUrl 函数
function _generateResourceUrl(name = '', {
    version = '',
    hasCss = true,
    basePath = '',
    jsPrefix = '',
    cssPrefix = ''
} = {}) {
    //如果模块名称是地址，直接返回相关地址
    if (name.indexOf('http:') >= 0) {
        return name;
    } else if (version) {
        return generateResourceObjectViaVersion({
            version,
            name
        });
    } else {
        // 默认资源生成逻辑
        const resourceUrlObj = {
            js: basePath + (jsPrefix ? jsPrefix + '/' : '') + name + '.js',
        };
        
        if (!hasCss) {
            console.log(name + ' no css file required');
        } else {
            resourceUrlObj.css = basePath + (cssPrefix ? cssPrefix + '/' : '') + name + '.css';
        }
        
        return resourceUrlObj;
    }
}

// 新增 getResolver 函数
let resolver = null;

// const getResolver = (generateResourceUrl) => {
//     const memoizedGenerateResourceUrlWithResolver = memoize(
//         generateResourceUrl || _generateResourceUrl,
//         (name, config) => name + JSON.stringify(config)
//     );
//     resolver = memoizedGenerateResourceUrlWithResolver;
//     return resolver;
// }

/**
 * 动态生成组件实例，并且挂载到body上
 * @param {*} Component 是组件配置对象
 * @param {*} props
 * TODO 将props传递下去
 */
export default function createVue(Component, props, dom, version, name) {
    const Vue = window.Vue && window.Vue.createApp ? window.Vue : (window.Vue3 || window.Vue);
    
    if (!Vue) {
        console.error('vue environment is not ready');
        return false;
    }
    
    // 传递props数据
    if (!Vue.createApp) {
        console.error('vue3 environment is not ready');
        return {};
        
        // vue3 需要直接传递属性，不能通过propsData传递
        const vm = Vue.createApp(Component, {
            ...(props || {}),
            propsData: {
                ...(props || {}),
                isRemote: true,
            }
        });
        vm.use(window.ElementPlus);
        vm.mount(dom);
        return vm;
    } else { // vue2
        // 借用Vue构造函数来动态生成组件实例
        const mixin = {
            created: function () {
                console.log('vue component created');
            }
        };
        
        console.log('vue定义', Component);
        if (typeof Component === 'string') {
            console.error(name, '组件定义不正确', Component);
        }
        
        // @ts-ignore
        const vm = ((window) => {
            console.log('实例化vue');
            try {
                if (isConstructor(Vue)) {
                    const ins = new Vue({
                        mixins: [mixin],
                        ...Component
                    });
                    return ins;
                }
            } catch (e) {
                console.error(e);
            }
        })(window);
        
        return vm;
    }
}

// 挂载react组件
function mountReactComponent({
    dom,
    App,
    RemoteComponent,
    propsData = {}
}) {
    function RootApp() {
        return React.createElement(React.StrictMode, null,
            React.createElement(App, null)
        );
    }
    
    delete propsData.undefined;
    console.log("渲染远程组件", propsData);
    
    if (dom) {
        if (typeof RemoteComponent.render === 'function') {
            // 交给对方去渲染
            window.ReactDOM.unmountComponentAtNode(dom);
            RemoteComponent.render({
                dom,
                propsData
            });
            
            return {
                destroy: () => {
                    window.ReactDOM.unmountComponentAtNode(dom);
                }
            };
        } else {
            const root = ReactDOM.createRoot(dom);
            root.render(React.createElement(RootApp, propsData));
            
            return {
                destroy: () => {
                    window.ReactDOM.unmountComponentAtNode(root);
                }
            };
        }
    } else {
        console.error('dom is not defined');
    }
}